"""
证件照服务模块

该模块提供完整的证件照处理服务，包括与Gradio API的交互、
文件存储管理、结果格式化等功能。

主要功能：
1. 证件照生成（标准照、高清照、透明背景照、排版照）
2. 社交媒体模板生成
3. 文件自动存储和管理
4. 支持多种尺寸和背景颜色
5. 水印添加功能
6. 多语言支持

使用示例：
    from api.id_photo_service import IDPhotoService
    
    service = IDPhotoService()
    result = service.process_photo(
        input_image="path/to/image.jpg",
        size_name="一寸",
        background_color="蓝色"
    )
"""

import os
import logging
from pathlib import Path
from typing import Dict, List, Optional, Union, Any
from datetime import datetime

from gradio_client import Client, handle_file

from config import (
    API_CONFIG, ID_PHOTO_SIZES, BACKGROUND_COLORS, 
    WATERMARK_CONFIG, SUPPORTED_LANGUAGES
)
from utils.file_manager import FileManager

logger = logging.getLogger(__name__)


class IDPhotoService:
    """
    证件照服务类
    
    提供完整的证件照处理服务，包括：
    - 与Gradio API交互
    - 文件存储管理
    - 结果格式化
    - 错误处理
    
    Attributes:
        client: Gradio API客户端
        file_manager: 文件管理器实例
        available_sizes: 可用的证件照尺寸列表
        background_colors: 可用的背景颜色列表
    """
    
    def __init__(self):
        """初始化证件照服务"""
        try:
            self.client = Client(API_CONFIG["gradio_endpoint"])
            self.file_manager = FileManager()
            self.available_sizes = ID_PHOTO_SIZES
            self.background_colors = BACKGROUND_COLORS
            
            logger.info("证件照服务初始化成功")
        except Exception as e:
            logger.error(f"证件照服务初始化失败: {e}")
            raise
    
    def get_available_sizes(self) -> List[Dict[str, Any]]:
        """
        获取可用的证件照尺寸列表
        
        Returns:
            尺寸信息列表，每个元素包含：
            - name: 尺寸名称
            - dimensions: 尺寸元组 (宽, 高)
            - description: 尺寸描述
        """
        return self.available_sizes
    
    def get_size_by_name(self, name: str) -> Optional[Dict[str, Any]]:
        """
        根据名称获取尺寸信息
        
        Args:
            name: 尺寸名称
            
        Returns:
            尺寸信息字典，如果未找到则返回None
        """
        for size in self.available_sizes:
            if size["name"] == name:
                return size
        return None
    
    def get_background_colors(self) -> List[str]:
        """
        获取可用的背景颜色列表
        
        Returns:
            背景颜色名称列表
        """
        return self.background_colors
    
    def _validate_inputs(
        self,
        input_image: str,
        size_name: str,
        background_color: str,
        language: str
    ) -> None:
        """
        验证输入参数
        
        Args:
            input_image: 输入图片路径
            size_name: 尺寸名称
            background_color: 背景颜色
            language: 语言代码
            
        Raises:
            ValueError: 如果参数无效
            FileNotFoundError: 如果输入文件不存在
        """
        # 验证输入文件
        if not os.path.exists(input_image):
            raise FileNotFoundError(f"输入图片不存在: {input_image}")
        
        # 验证尺寸
        if not self.get_size_by_name(size_name):
            available_names = [s["name"] for s in self.available_sizes]
            raise ValueError(f"无效的尺寸: {size_name}。可用尺寸: {available_names}")
        
        # 验证背景颜色
        if background_color not in self.background_colors:
            raise ValueError(f"无效的背景颜色: {background_color}。可用颜色: {self.background_colors}")
        
        # 验证语言
        if language not in SUPPORTED_LANGUAGES:
            raise ValueError(f"不支持的语言: {language}。支持的语言: {SUPPORTED_LANGUAGES}")
    
    def _extract_path(self, item: Any) -> Optional[str]:
        """
        从API返回结果中提取文件路径
        
        Args:
            item: API返回的项
            
        Returns:
            文件路径，如果无法提取则返回None
        """
        if isinstance(item, str):
            return item
        elif isinstance(item, dict):
            if item.get('__type__') == 'update':
                return item.get('value')
            elif 'image' in item:
                return item['image']
            elif 'path' in item:
                return item['path']
        return None
    
    def _save_result_files(
        self,
        result_paths: Dict[str, Optional[str]],
        size_name: str,
        original_filename: str,
        original_image_path: str,
        openid: str = None
    ) -> Dict[str, Union[str, List[Dict[str, str]]]]:
        """
        保存处理结果文件

        Args:
            result_paths: 结果文件路径字典
            size_name: 尺寸名称
            original_filename: 原始文件名
            original_image_path: 原始图片路径
            openid: 用户openid，用于按用户分目录存储
            
        Returns:
            保存后的文件信息字典
        """
        saved_files = {}
        
        # 如果提供了openid，先删除该用户的所有旧文件
        if openid:
            self._cleanup_user_files(openid)
        
        # 保存原图
        if original_image_path and os.path.exists(original_image_path):
            info = self.file_manager.save_file(
                original_image_path, 'original', size_name, f"original_{original_filename}", openid
            )
            # 处理路径，仅保留子目录和文件名
            from pathlib import Path
            saved_path = Path(info['saved_path'])
            project_root = Path(__file__).parent.parent.parent
            relative_path = saved_path.relative_to(project_root)
            parts = list(relative_path.parts)
            if 'openid' in parts:
                idx = parts.index('openid')
                if len(parts) > idx + 2:
                    new_parts = parts[idx+1:]
                    saved_files['original'] = '/openid/' + '/'.join(new_parts)

        # 保存标准证件照
        if result_paths.get('standard'):
            info = self.file_manager.save_file(
                result_paths['standard'], 'standard', size_name, original_filename, openid
            )
            # 处理路径，仅保留子目录和文件名
            from pathlib import Path
            saved_path = Path(info['saved_path'])
            project_root = Path(__file__).parent.parent.parent
            relative_path = saved_path.relative_to(project_root)
            parts = list(relative_path.parts)
            if 'openid' in parts:
                idx = parts.index('openid')
                if len(parts) > idx + 2:
                    new_parts = parts[idx+1:]
                    saved_files['standard'] = '/openid/' + '/'.join(new_parts)

        # 保存高清证件照
        if result_paths.get('hd'):
            info = self.file_manager.save_file(
                result_paths['hd'], 'hd', size_name, original_filename, openid
            )
            # 处理路径，仅保留子目录和文件名
            from pathlib import Path
            saved_path = Path(info['saved_path'])
            project_root = Path(__file__).parent.parent.parent
            relative_path = saved_path.relative_to(project_root)
            parts = list(relative_path.parts)
            if 'openid' in parts:
                idx = parts.index('openid')
                if len(parts) > idx + 2:
                    new_parts = parts[idx+1:]
                    saved_files['hd'] = '/openid/' + '/'.join(new_parts)

        # 保存透明背景标准照
        if result_paths.get('transparent'):
            info = self.file_manager.save_file(
                result_paths['transparent'], 'transparent', size_name, original_filename, openid
            )
            # 处理路径，仅保留子目录和文件名
            from pathlib import Path
            saved_path = Path(info['saved_path'])
            project_root = Path(__file__).parent.parent.parent
            relative_path = saved_path.relative_to(project_root)
            parts = list(relative_path.parts)
            if 'openid' in parts:
                idx = parts.index('openid')
                if len(parts) > idx + 2:
                    new_parts = parts[idx+1:]
                    saved_files['transparent'] = '/openid/' + '/'.join(new_parts)

        # 保存透明背景高清照
        if result_paths.get('transparent_hd'):
            info = self.file_manager.save_file(
                result_paths['transparent_hd'], 'transparent_hd', size_name, original_filename, openid
            )
            # 处理路径，仅保留子目录和文件名
            from pathlib import Path
            saved_path = Path(info['saved_path'])
            project_root = Path(__file__).parent.parent.parent
            relative_path = saved_path.relative_to(project_root)
            parts = list(relative_path.parts)
            if 'openid' in parts:
                idx = parts.index('openid')
                if len(parts) > idx + 2:
                    new_parts = parts[idx+1:]
                    saved_files['transparent_hd'] = '/openid/' + '/'.join(new_parts)

        # 保存排版照
        if result_paths.get('layout'):
            info = self.file_manager.save_file(
                result_paths['layout'], 'layout', size_name, original_filename, openid
            )
            # 处理路径，仅保留子目录和文件名
            from pathlib import Path
            saved_path = Path(info['saved_path'])
            project_root = Path(__file__).parent.parent.parent
            relative_path = saved_path.relative_to(project_root)
            parts = list(relative_path.parts)
            if 'openid' in parts:
                idx = parts.index('openid')
                if len(parts) > idx + 2:
                    new_parts = parts[idx+1:]
                    saved_files['layout'] = '/openid/' + '/'.join(new_parts)
        
        # 处理社交媒体模板 - 直接删除不保存
        social_media_files = []
        if result_paths.get('social_media'):
            for idx, social_item in enumerate(result_paths['social_media']):
                if isinstance(social_item, dict) and 'image' in social_item:
                    image_path = social_item['image']
                    # 直接删除文件而不是保存
                    if image_path and os.path.exists(image_path):
                        try:
                            os.remove(image_path)
                            logger.info(f"已删除社交媒体模板文件: {image_path}")
                        except Exception as e:
                            logger.warning(f"删除社交媒体模板文件失败: {e}")
                    
                    # 返回空路径，表示文件已删除
                    social_media_files.append({
                        'image': None,
                        'caption': social_item.get('caption', '')
                    })
        
        saved_files['social_media'] = social_media_files
        return saved_files
    
    def process_photo(
        self,
        input_image: str,
        size_name: str = "一寸",
        background_color: str = "蓝色",
        watermark_option: str = "不添加",
        watermark_text: str = "",
        language: str = "zh",
        openid: str = None
    ) -> Dict[str, Any]:
        """
        处理证件照
        
        这是主要的处理函数，负责：
        1. 验证输入参数
        2. 调用Gradio API处理图片
        3. 保存处理结果
        4. 返回格式化的结果
        
        Args:
            input_image: 输入图片路径
            size_name: 尺寸名称（如"一寸"）
            background_color: 背景颜色（如"蓝色"）
            watermark_option: 水印选项（"不添加"或"添加"）
            watermark_text: 水印文字（可选）
            language: 语言代码（"zh", "en", "ko", "ja"）
            
        Returns:
            处理结果字典：
            {
                'success': 是否成功,
                'message': 处理消息,
                'data': {
                    'standard': 标准证件照路径,
                    'hd': 高清证件照路径,
                    'transparent_standard': 透明标准照路径,
                    'transparent_hd': 透明高清照路径,
                    'layout': 排版照路径,
                    'social_media': 社交媒体模板列表,
                    'metadata': 处理元数据
                },
                'timestamp': 处理时间戳
            }
        """
        start_time = datetime.now()
        
        try:
            # 验证输入参数
            self._validate_inputs(input_image, size_name, background_color, language)
            
            # 获取尺寸信息
            size_info = self.get_size_by_name(size_name)
            width, height = size_info["dimensions"]
            
            # 调用API处理图片
            logger.info(f"开始处理证件照: {input_image}, 尺寸: {size_name}, 背景: {background_color}")
            
            result = self.client.predict(
                input_image=handle_file(input_image),
                mode_option="尺寸列表",
                size_list_option=f"{size_name}\t\t({width}, {height})",
                color_option=background_color,
                render_option="纯色",
                image_kb_options="不设置",
                custom_color_R=0,
                custom_color_G=0,
                custom_color_B=0,
                custom_color_hex_value="000000",
                custom_size_height=height,
                custom_size_width=width,
                custom_size_height_mm=35,
                custom_size_width_mm=25,
                custom_image_kb=50,
                language=language,
                matting_model_option="modnet_photographic_portrait_matting",
                watermark_option=watermark_option,
                watermark_text=watermark_text,
                watermark_text_color="#FFFFFF",
                watermark_text_size=20,
                watermark_text_opacity=0.15,
                watermark_text_angle=30,
                watermark_text_space=25,
                face_detect_option="retinaface-resnet50",
                head_measure_ratio=0.2,
                top_distance_max=0.12,
                whitening_strength=2,
                image_dpi_option="不设置",
                custom_image_dpi=300,
                brightness_strength=0,
                contrast_strength=0,
                sharpen_strength=0,
                saturation_strength=0,
                plugin_option=["排版照裁剪线"],
                print_switch="六寸",
                api_name="/process"
            )
            
            # 解析结果
            result_paths = {}
            
            # 提取各种证件照路径
            if len(result) > 0:
                result_paths['standard'] = self._extract_path(result[0])
            if len(result) > 1:
                result_paths['hd'] = self._extract_path(result[1])
            if len(result) > 2:
                result_paths['transparent_standard'] = self._extract_path(result[2])
            if len(result) > 3:
                result_paths['transparent_hd'] = self._extract_path(result[3])
            if len(result) > 4:
                result_paths['layout'] = self._extract_path(result[4])
            
            # 处理社交媒体模板
            social_media = []
            if len(result) > 5:
                social_item = result[5]
                if isinstance(social_item, dict) and social_item.get('__type__') == 'update':
                    social_list = social_item.get('value', [])
                    if isinstance(social_list, list):
                        for item in social_list:
                            if isinstance(item, dict):
                                social_media.append({
                                    'image': self._extract_path(item),
                                    'caption': item.get('caption', '')
                                })
            result_paths['social_media'] = social_media
            
            # 保存文件
            original_filename = Path(input_image).name
            saved_files = self._save_result_files(result_paths, size_name, original_filename, input_image, openid)
            
            # 构建响应
            processing_time = (datetime.now() - start_time).total_seconds()
            
            # 计算删除日期
            from datetime import timedelta
            delete_at = datetime.now() + timedelta(days=7)
            
            return {
                'success': True,
                'message': '证件照处理成功',
                'data': {
                    **saved_files,
                    'metadata': {
                        'original_image': input_image,
                        'size': size_name,
                        'background_color': background_color,
                        'watermark': watermark_option == "添加",
                        'watermark_text': watermark_text,
                        'language': language,
                        'processing_time_seconds': processing_time,
                        'created_at': datetime.now().isoformat(),
                        'delete_at': delete_at.isoformat()
                    }
                },
                'timestamp': datetime.now().isoformat()
            }
            
        except Exception as e:
            logger.error(f"处理证件照失败: {e}")
            return {
                'success': False,
                'message': f'处理失败: {str(e)}',
                'data': None,
                'timestamp': datetime.now().isoformat()
            }
    
    def get_storage_stats(self) -> Dict[str, Any]:
        """
        获取存储统计信息
        
        Returns:
            存储统计信息
        """
        return self.file_manager.get_storage_stats()
    
    def cleanup_old_files(self, days: Optional[int] = None) -> Dict[str, Any]:
        """
        手动触发清理过期文件
        
        Args:
            days: 保留天数，如果为None则使用默认值
            
        Returns:
            清理统计信息
        """
        return self.file_manager.cleanup_old_files(days)
    
    def _cleanup_user_files(self, openid: str) -> None:
        """
        清理指定用户的所有旧文件
        
        Args:
            openid: 用户openid
        """
        try:
            from pathlib import Path
            import shutil
            
            base_dir = self.file_manager.base_dir
            user_dir = base_dir / openid
            
            if not user_dir.exists():
                return
                
            # 删除用户目录下的所有文件和子目录
            for subdir_name in self.file_manager.subdirs.values():
                subdir_path = user_dir / subdir_name
                if subdir_path.exists():
                    shutil.rmtree(subdir_path)
                    
            logger.info(f"已清理用户 {openid} 的所有旧文件")
            
        except Exception as e:
            logger.error(f"清理用户文件失败: {e}")

    def list_processed_files(self, file_type: Optional[str] = None, openid: str = None) -> List[Dict[str, Any]]:
        """
        列出已处理的文件

        Args:
            file_type: 文件类型过滤
            openid: 用户openid，如果提供则只列出该用户的文件
            
        Returns:
            文件信息列表
        """
        return self.file_manager.list_files(file_type, openid)